package com.zplus.managers.petservices.utils;

import com.zplus.managers.petservices.entities.EntityBase;
import com.zplus.managers.petservices.entities.User;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PagingFactory
{
    private List<? extends EntityBase> data;

    // save how much pages can data produce
    private int totalPages;

    // save previous page num
    private int prevPage;

    // save how many items can a signle page hold.
    private int metaData;

    /**
     * create paging facotry
     * @param data data to be paging
     * @param pageSize the number of item shows at a page
     */
    public PagingFactory(List<? extends EntityBase> data, int pageSize)
    {
        this.data = data;
        this.metaData = pageSize;
        setTotalpages(data.size(), pageSize);
    }

    /**
     * get given page
     * @param pageIndex target page index
     * @return page content, null otherwise
     */
    public Page getPage(int pageIndex)
    {
        Page page = new Page();
        // validation
        if(pageIndex > totalPages || pageIndex <= 0)
        {
            page.setState(PageState.OUTOFINDEX);
        }
        List<EntityBase> content = new ArrayList<>();
        //load page content
        for(int i = (pageIndex - 1) * metaData, cnt = 1; cnt <= metaData && i < data.size(); i++, cnt++)
        {
            content.add(data.get(i));
        }
        // load page content and set status
        page.load(content, getTotalPages(), pageIndex, data.size());
        page.setState(PageState.NORMAL);
        // update prevpage data
        prevPage = pageIndex;
        return page;
    }

    /**
     * get the next page
     * @return next page content, null otherwise
     */
    public Page nextPageMap()
    {
        Page page = new Page();
        // validation
        if(prevPage >= totalPages)
        {
            page.setState(PageState.OUTOFINDEX);
            return page;
        }
        // get page content
        Map<String, EntityBase> map = new HashMap<>();
        EntityBase tmp;
        for(int i = prevPage * metaData, cnt = 0; i < data.size() && cnt < metaData; i++, cnt++)
        {
            tmp = data.get(i);
            map.put("key_"+tmp.getId(), tmp);
        }
        // load page content
        page.load(map,totalPages, prevPage + 1);
        // update prevpage
        prevPage ++;
        return page;
    }

    /**
     * not allowed
     * @return
     */
    public Page nextPage()
    {
        Page page = new Page();
        // validation
        if(prevPage >= totalPages)
        {
            page.setState(PageState.OUTOFINDEX);
            return page;
        }
        // get page content
        List<EntityBase> tmp = new ArrayList<>();
        for(int i = prevPage * metaData, cnt = 0; i < data.size() && cnt < metaData; i++, cnt++)
        {
            tmp.add(data.get(i));
        }
        // load page content
        page.load(tmp, totalPages, prevPage + 1, data.size());
        // update prevpage
        prevPage ++;
        return page;
    }

    /**
     * get the previous page
     * @return prev page content, null otherwise
     */
    @Deprecated
    public Page prevPage()
    {
        Page page = new Page();
        // validation, if prevpage already at page 1
        if (prevPage <= 0)
        {
            page.setState(PageState.OUTOFINDEX);
            return page;
        }
        // get page data
        Map<String, EntityBase> map = new HashMap<>();
        EntityBase tmp;
        for(int i = (prevPage - 1) * metaData, cnt = 0; i < data.size() && cnt < metaData; i++, cnt++)
        {
            tmp = data.get(i);
            map.put("key_"+tmp.getId(), tmp);
        }
        // load page content
        page.load(map,totalPages, prevPage);
        // update prevpage
        prevPage --;
        page.setState(PageState.NORMAL);
        return page;
    }


    /**
     * reassign the page size
     * new page content will be given at next page requesting
     * @param size new page size
     */
    public void resizePage(int size)
    {
        this.metaData = size;
        setTotalpages(data.size(), size);
        // prevent prevpage is larger than total page
        if (prevPage > totalPages)
            prevPage = 0;
    }

    /**
     *  set total pages
     * @param totalItems sum of items
     * @param metaData the number of items that a page can show
     */
    private void setTotalpages(int totalItems, int metaData)
    {
        if (data.size() % metaData == 0)
            totalPages = data.size() / metaData;
        else
            totalPages = data.size() / metaData + 1;
    }

    /**
     * return previous page index
     * @return page index
     */
    public int whereAmI()
    {
        return prevPage;
    }

    public int getTotalPages()
    {
        return totalPages;
    }
}
